At present, a hierarchy (called a multitier architecture) for delivering services to clients comprises three basic elements: client browser, application server and database. See FIG. 1. For example, when a subscriber wants to use a special service, he can download it through the browser (1). The subscriber defines the service in the browser, which sends the service order to the application server (2). The application server executes the service and sends the desired response to the client server. The application server may use the database (3) (or databases) if the application server needs specific data or programs for executing the service.
FIG. 2 shows an example of how a mobile user (5) utilizes services of the application server (2). An intelligent network (4) provides the services to the user. The network can provide the same service to several users (millions of users) at a time. In this example, it is worth of noticing that the intelligent network is more in the role of the user of the services than just a plain transmission network.
Application servers (a server is a device, connected to a network, that provides services, i.e. applications, to network users by managing shared resources) on a network run thousands of different services for up to millions of simultaneous users. Usually the services contain one or more binary format files (executable codes, data). The common way is to use a programming language, such as Java, to form services and virtual machine environment, such as Java virtual machine, to execute services. In the Java environment binary format files are mostly called classes. A class file contains Java virtual machine instructions and a symbol table, as well as other ancillary information. Two or more services can share the same classes.
For understanding the description of the invention, basic structures of the Java language should be kept in mind. Java is an object-oriented programming language. An object is a software component that usually contains executive codes and data. In an object-oriented language actual objects are not defined, but classes of objects are defined. A class is a template for multiple objects with similar features. It can be said that a class describes all common features for all objects in the class. So, a single object is a concrete representation of the class, in other words an instance.
Methods are functions, i.e. executable codes that operate on a class or an object. A stream is a path of communication between the source Of some information and its destination. Java contains several inputstream and outputstream classes for defining different streams. Serializing is a feature in Java environment that makes it possible to save a state of an instance of the class (the concrete representation of a class) in the form of a byte-line. Serialized instances can be deserialized making it possible to use the saved class representation later. To sum up, a Java application comprises classes, which refer to objects. One of the classes is the “root” class, which contains basic methods of the application and makes it possible to get the other classes that belong to the application.
Classes may change occasionally. Old classes may contain errors that are desired to be eliminated, or it may be desired to have a more efficient class version. Different service providers may also use same names for different classes. Due to these items, a service may use a different class version than it has used normally. Let's take an example where a subscriber is using an old browser to get a special service. However, the service has updated for a new browser after the latest subscriber's use of service, and due to this the service do not work properly. Another example can be when a service consists of several classes. Updating one or more classes may cause incompatibilities among the classes in the service. Tedious testing is required for checking compatibility matters between old and new class versions.
In Microsoft WindoWS™ environment and also in Unix environment there are dynamic link libraries, DLLs, comprising reusable software components. The software components needed by applications are distributed as DLLs. Th ere can b e a multitude of applications that use same reusable software components. In other words, a dynamic link library (DLL) is a collection of small programs, which can be called when needed by the executable program or process that is running. For example, the DLL lets the executable program to communicate with a specific device, such as a printer, or it may contain source code to do particular functions.
Furthermore, for example, a program (exe) needs to stem a certain word within a character string it can call the DLL file that contains the function with parameters and a call function. The DLL will tell the executable program the stem form of the word. This allows the executable program to be small in size and it does not need to rewrite the function that has already been written. This allows that any program, needing to stem a word, does not have to write all the source code and to save space on secondary storage as well. DLLs in this fashion are also known as shared files.
The advantage of DLL files is that (because they do not get loaded into random access memory (RAM) together with the main program) space is saved in RAM. Only when and if a DLL file is called, it is loaded. For example, when you are editing a Microsoft Word™ document, the printer driver DLL file does not need to be loaded into RAM. If you decide to print the document, then the printer DLL file is loaded and run.
All in all a DLL is an executable file that cannot be run on it's own, it can only be run from inside an executable file.
When an application is executed it is necessary that the components match the application. For example, in Microsoft Windows™ environment the matching of components and the application is achieved so that when an application is compiled or linked, it recalls the version numbers of the DLLs present in the programming environment. This means that the application is labelled with the version numbers of the DLLs used. When an application is started, it checks the version numbers of the DLLs present in its current execution environment, that is, such as the current computer. If the version numbers present are older than the stamps or labels on the application, the application refuses to run.
In the Microsoft Windows™ environment there can be different versions of components. This is achieved by having path definitions that have different precedencies. The alternative DLLs are stored in different folders. It is usual in many environments that the DLLs and the applications can be installed separately.
It may happen that an application must be run using the components against which it has originally been written and tested. This means, for example, that their versions do not match.
If an application starts to use new versions of installed DLLs problems may occur. This is due to the fact that in the application there can be faults that are corrected accidentally by the old DLLs. Alternatively, the internal logic of a DLL may have change in a way that is not reflected by having new parameters in the interface definition etc.
The problem is worse in service hotel environments, such as network servers, where the applications are developed elsewhere and installed later on to a different execution environment, for example, on a different server. Basically, each possible combination of an application version and its components versions should have to be checked.
In Java, it is possible to serialize and deserialize objects, which means that an object can be transferred to another virtual machine, or the object can later on be reinstantiated having the same state as by the time it was serialized. The state comprises the attribute values of the object attributes and any other objects instantiated within the object prior to serialization.
Also objects referred to within the object are serialized and reinstantiated along the object. The Java property of object serialization and reinstantiation can be used for many purposes, for instance, user interface objects can be instantiated with predefined components such as scrollers, buttons and menus—these are represented as linked subordinate objects that are as well serialized along the object—and certain initial data values.
In Java there is also version control, which sees that deserialized objects are of the same class version as in their original environment. The version control is achieved so that with each serialized object is associated a SUID (Stream Unique Identifier), forming a serial version unique identifier that is stored in addition to the class name and object attribute values in the serialized form. The SUID is a hash value computed on the text format class interface definition comprising method signatures and serialized attributes. In the receiving environment there is a compiled class having the same interface definition. The Java deserializer computes a similar hash value of the target class in the receiving environment. Thereafter, the deserializer checks that the hash values agree.
In Java it is possible to use class loaders, i.e. it is possible to load compiled bytecode comprising a class into the virtual machine. A class can be loaded, for instance, from local filesystem i.e. a specified directory accessed by the computer running the virtual machine. A class can as well be loaded over the Internet using HTTP (Hypertext Transfer Protocol) or FTP (File Transfer Protocol). In many applications it is also useful to store classes into databases. In a virtual machine there can be several class loaders: at least the primordial class loader, that is, the default class loader, and possibly some customized class loaders. The customized class loaders can be used to affect the process of class loading. The benefit of Java class loader mechanism is that the use of customized class loaders is not visible for the programmer when classes to be loaded using the customized loader are instantiated. The classes are just instantiated normally like any new class instances. By having several class loaders, it is possible to have at least two versions of a class having the same name. These two versions of the class can happily co-exist within the virtual machine. Each object memorizes its class loader.
The situation where in a virtual machine there exists two objects within same class names but different class bytecode versions cannot be achieved with just the primodial class loader. The classes have to be loaded using alternative class loaders.
Now the serialization and deserialization process is considered from the service execution environment point of view. A service execution environment is executing application programs that determine the behaviour of a service for an end-user. The service can be, for instance, a subscriber service within an intelligent telecommunications network or it can be a WWW (World Wide Web) service executing process within a WWW-server environment.
A service can be seen as an instance of a highest-level object. The class code for the object and the objects attribute values determine the behaviour of the service. Of course, the behaviour can be achieved using subordinate objects which are referenced from the highest level object, by calling methods on these objects. References to these objects can be obtained via data read from databases or by just instantiating new objects. The instantiated subordinate objects are deserialized along with the service object itself. As explained before, in large service execution environments there can exist several versions of various subordinate object classes commonly used by different services. When an instance of a service is created, for instance, for a subscriber invoking the service, an initial object instance is formed for the service instance. It is beneficial to instantiate the service instance by deserializing an object instance so that certain initial attribute values can be obtained without unnecessary value initializations and object instantiation. When deserializing the object instance for the service instance, it is necessary to serialize correct versions of the subordinate objects referenced by the service.
This could be done by using object SUIDs to find the correct classes. However, this solution has certain drawbacks such as that the solution only applies for the classes for which there are data references. The solution does not apply to classes that are referenced on code level.